package query.select

import ast.expr.SqlIdentifierExpr
import ast.statement.select.SqlSelectQuery
import ast.statement.select.SqlWithItem
import ast.statement.select.SqlWithSelect
import database.DBConnection
import dsl.column
import database.DB
import util.toSqlString
import visitor.getQueryExpr
import java.sql.Connection

/**
 * with select语句dsl类
 * @property db DB 数据库类型
 * @property conn Connection? 数据库连接
 * @property isTransaction Boolean 是否是事务
 * @property dbConnection DBConnection? 基础查询类
 * @property withSelect SqlWithSelect with select语法树
 */
class WithSelect(
    var db: DB = DB.MYSQL,
    override var conn: Connection? = null,
    override var isTransaction: Boolean = false,
    override var dbConnection: DBConnection? = null
) :
    SelectQueryImpl() {
    constructor(db: DB) : this(db, null, false, null)

    private var withSelect = SqlWithSelect()

    /**
     * 递归查询
     * @return WithSelect with查询dsl
     */
    fun recursive(): WithSelect {
        this.withSelect.recursive = true
        return this
    }

    /**
     * 向with中添加一个子查询
     * @param name String 查询名称
     * @param columns List<String> 字段名列表
     * @param query SelectQuery 查询dsl
     * @return WithSelect with查询dsl
     */
    fun add(name: String, columns: List<String>, query: SelectQuery): WithSelect {
        val withItem = SqlWithItem(
            getQueryExpr(column(name), db).expr,
            query.getSelect(),
            columns.map { SqlIdentifierExpr(it) })

        this.withSelect.with.add(withItem)
        return this
    }

    /**
     * 向with中添加一个子查询
     * @param name String 查询名称
     * @param query SelectQuery 查询dsl
     * @param columns Array<out String> 字段名列表
     * @return WithSelect with查询dsl
     */
    fun add(name: String, query: SelectQuery, vararg columns: String): WithSelect {
        return add(name, columns.toList(), query)
    }

    /**
     * with查询中最终查询
     * @param query [@kotlin.ExtensionFunctionType] Function1<Select, SelectQuery> 查询dsl
     * @return WithSelect with查询dsl
     */
    fun select(query: Select.() -> SelectQuery): WithSelect {
        withSelect.query = query(Select(db)).getSelect()
        return this
    }

    /**
     * 获取sql语法树
     * @return SqlSelectQuery sql语法树
     */
    override fun getSelect(): SqlSelectQuery {
        return this.withSelect
    }

    /**
     * 获取数据库类型
     * @return DB 数据库类型
     */
    override fun getDbType(): DB {
        return this.db
    }

    /**
     * 生成sql语句
     * @return String sql语句
     */
    override fun sql(): String {
        return toSqlString(withSelect, db)
    }
}